﻿using System;
using GameEngine.Libs;
using System.Collections.Generic;
using System.Xml.Linq;

namespace GameEngine.Model.Data
{
    public class ThingTypeVO<IdType> : IThingTypeVO<IdType>
        where IdType : IComparable<IdType>
    {
        //public int Id { get; set; }
        public IThingTypeVOId Id { get; protected set; }
        public IViewVOId<IdType> ViewId { get; set; }
        public List<IViewStateVO> ViewStates { get; set; }

        //TODO health etc
        public ThingTypeVO(IThingTypeVOId id)
        {
            Id = id;
        }

        public ThingTypeVO() { }

        public virtual XElement createSerializeObject() {
            //return Serializer.Serialize(VO);
            XDocument doc = new XDocument();
            XElement mainNode = new XElement("ThingTypeVO");
            mainNode.SetAttributeValue("Class", GetType());

            {
                XElement node = new XElement("Id", new XAttribute("Class", Id.GetType()));
                node.Add(Id.Serialize());
                mainNode.Add(node);
            }
            {
                XElement node = new XElement("ViewId", new XAttribute("Class", ViewId.GetType()));
                node.Add(ViewId.Serialize());
                mainNode.Add(node);
            }
            {
                XElement node = new XElement("ViewStates");
                if(ViewStates!=null)
                foreach (var row in ViewStates)
                {
                    XElement rowXml = new XElement("ViewStateId", new XAttribute("Class", row.GetType()));
                    rowXml.Add(row.Value);
                    node.Add(rowXml);
                }
                mainNode.Add(node);
            }
            return mainNode;
        }

        public string Serialize()
        {
            return createSerializeObject().ToString();
        }

        public virtual void DeSerialize(string serializedString)
        {
            XElement mainNode = XElement.Parse(serializedString);
            foreach (XElement node in mainNode.Nodes())
            {
                switch (node.Name.LocalName)
                {
                    case "Id":
                        {
                            var className = node.Attribute("Class").Value;
                            var classType = Type.GetType(className);
                            var instance = Activator.CreateInstance(classType) as IThingTypeVOId;
                            instance.DeSerialize(node.Value);
                            Id = instance;
                        }
                        break;
                    case "ViewId":
                        {
                            var className = node.Attribute("Class").Value;
                            var classType = Type.GetType(className);
                            var instance = Activator.CreateInstance(classType) as IViewVOId<IdType>;
                            instance.DeSerialize(node.Value);
                            ViewId = instance;
                        }
                        break;
                    case "ViewStates":
                        {
                            foreach (var row in node.Elements())
                            {
                                var className = row.Attribute("Class").Value;
                                var classType = Type.GetType(className);
                                var instance = Activator.CreateInstance(classType, node.Value) as IViewStateVO;
                                ViewStates.Add(instance);
                            }
                        }
                        break;
                }
            }
        }
    }

    public class ThingTypeVOId : Id<int>, IThingTypeVOId{
        public ThingTypeVOId(int id) : base(id) { }

        public ThingTypeVOId() { }
    }

    public class SensingThingTypeVO<IdType> : ThingTypeVO<IdType>, ISensingThingTypeVO<IdType>
        where IdType : IComparable<IdType>
    {
        //n guarda estado de variaveis calculadas on the fly

        public SensingThingTypeVO() { }

        public SensingThingTypeVO(IThingTypeVOId id) :
            base(id)
        {
            //Type = "SensingThingTypeVO";
        }
    }

    public class MovingThingTypeVO<IdType> : SensingThingTypeVO<IdType>, IMovingThingTypeVO<IdType> 
        where IdType : IComparable<IdType>
    {
        public float Velocity { get; set; }

        public MovingThingTypeVO(IThingTypeVOId id) :
            base(id)
        {
            //Type = "MovingThingTypeVO";
            Velocity = 0.1f;
        }

        public MovingThingTypeVO(){}

        public override XElement createSerializeObject()
        {
            XElement mainNode = base.createSerializeObject();
            {
                XElement node = new XElement("Velocity", new XAttribute("Class", Velocity.GetType()));
                node.Add(new XCData(Serializer.Serialize(Velocity)));
                mainNode.Add(node);
            }
            return mainNode;
        }

        public override void DeSerialize(string serializedString)
        {
            base.DeSerialize(serializedString);
            XElement mainNode = XElement.Parse(serializedString);
            foreach (XElement node in mainNode.Nodes())
            {
                switch (node.Name.LocalName)
                {
                    case "Velocity":
                        {
                            Velocity = (float)Serializer.DeSerialize(typeof(float), node.Value);
                        }
                        break;
                }
            }
        }
    }

    public class ThinkingThingTypeVO<IdType>:MovingThingTypeVO<IdType>, IThinkingThingTypeVO<IdType> 
        where IdType : IComparable<IdType>
    {
        //TODO propriedades do brain, inputs outputs, conhecimentos adquirirdos
        public ThinkingThingTypeVO(IThingTypeVOId id) :
            base(id)
        {
            //Type = "ThinkingThingTypeVO";
            //Brain = new NeuralNetwork(4,new int[]{6,6,5});
            //Brain.randomizeAll();
        }
    
        public ThinkingThingTypeVO(){}
    }
}
